package io.gitee.hefren.hhconfig.server.service.impl;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.gitee.hefren.hhconfig.server.beans.Configs;
import io.gitee.hefren.hhconfig.server.dao.HhConfigServerMapper;
import io.gitee.hefren.hhconfig.server.service.HhConfigServerService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * @Date 2024/5/26
 * @Author lifei
 */
@Service
public class HhConfigServerServiceImpl implements HhConfigServerService {

    private static final Logger log = LoggerFactory.getLogger(HhConfigServerServiceImpl.class);

    @Resource
    private HhConfigServerMapper hhConfigServerMapper;
    private final MultiValueMap<String, DeferredResult<Long>> deferredResultVersions = new LinkedMultiValueMap<>();


    @Override
    public List<Configs> findConfigsList(String capp, String cenv, String cnamespace) {
        List<Configs> result = Lists.newArrayList();
        List<Configs> configsList = hhConfigServerMapper.findConfigsList(capp, cenv, cnamespace);
        if (Objects.nonNull(configsList) && !configsList.isEmpty()) {
            result.addAll(configsList);
        }
        return result;
    }

    @Override
    public List<Configs> updateOrInsertConfigsList(String capp, String cenv, String cnamespace, Map<String, String> kvMap) {
        List<Configs> result = Lists.newArrayList();
        if (Objects.isNull(kvMap) || kvMap.isEmpty()) {
            return result;
        }
        Long newVersion = updateOrInsertConfigsVersion(capp, cenv, cnamespace, System.currentTimeMillis());
        List<Configs> list = kvMap.keySet().stream().map(ckey -> new Configs(capp, cenv, cnamespace, ckey, kvMap.get(ckey))).toList();
        for (Configs configs : list) {
            Configs oldConfigs = hhConfigServerMapper.findConfigs(capp, cenv, cnamespace, configs.getCkey());
            if (Objects.isNull(oldConfigs) || Objects.isNull(oldConfigs.getCkey())) {
                hhConfigServerMapper.insertConfigs(configs);
            } else {
                hhConfigServerMapper.updateConfigs(configs);
            }
        }
        updateDeferredResult(capp, cenv, cnamespace, newVersion);
        return findConfigsList(capp, cenv, cnamespace);
    }

    private void updateDeferredResult(String capp, String cenv, String cnamespace, Long newVersion) {
        String key = genkey(capp, cenv, cnamespace);
        List<DeferredResult<Long>> deferredResults = deferredResultVersions.get(key);
        if (Objects.isNull(deferredResults) || deferredResults.isEmpty()) {
            return;
        }
        for (DeferredResult<Long> deferredResult : deferredResults) {
            deferredResult.setResult(newVersion);
        }
    }

    @Override
    public Long updateOrInsertConfigsVersion(String capp, String cenv, String cnamespace, Long cversion) {
        Long oldVersion = hhConfigServerMapper.findConfigsVersion(capp, cenv, cnamespace);
        if (Objects.isNull(oldVersion)) {
            hhConfigServerMapper.insertConfigsVersion(capp, cenv, cnamespace, cversion);
        } else {
            hhConfigServerMapper.updateConfigsVersion(capp, cenv, cnamespace, cversion);
        }
        return cversion;
    }

    @Override
    public Long findConfigsVersion(String capp, String cenv, String cnamespace) {
        Long cVersion = hhConfigServerMapper.findConfigsVersion(capp, cenv, cnamespace);
        return Optional.ofNullable(cVersion).orElse(-1L);
    }

    @Override
    public DeferredResult<Long> deferredResultVersion(String capp, String cenv, String cnamespace) {
        String key = genkey(capp, cenv, cnamespace);
        DeferredResult<Long> result = new DeferredResult<>(4000L);
        result.onCompletion(()->{
            log.debug("===> deferred completion, key: {}", key);
            deferredResultVersions.remove(key);
        });
        result.onTimeout(()->{
            log.debug("===> deferred timeout, key: {}", key);
            deferredResultVersions.remove(key);
        });
        result.onError((e)->{
            log.debug("===> deferred error: {}", e.getMessage());
            deferredResultVersions.remove(key);
        });
        deferredResultVersions.add(key, result);
        return result;
    }

    private static String genkey(String capp, String cenv, String cnamespace) {
        String key = Strings.lenientFormat("%s_%s_%s", capp, cenv, cnamespace);
        return key;
    }


}
